/*
	Written By Pradipna Nepal and Sanjay Giri
	www.pradsprojects.com

	Copyright (C) 2011 Prads Projects
	Please read COPYING.txt included along with this source code for more detail.
	If not included, see http://www.gnu.org/licenses/
*/

#ifndef LIBEMUCPUCORE_H
#define LIBEMUCPUCORE_H

#include "libEmuGraphics.h"
#include "libEmuROMLoader.h"
#include "libEmuInputs.h"
using namespace ROMLoader;

//CPU Registers
struct REGISTERS {
	unsigned int PC, SP, R[16];
	unsigned char flag;
};

//Flag Mask
#define FLAG_C			2		//Carry/Borrow Flag (bit 1)
#define FLAG_Z			4		//Zero Flag (bit 2)
#define FLAG_O			0x40	//Overflow Flag (bit 6)
#define FLAG_N			0x80	//Negative Flag (bit 7)

//For Flag O
#define POSITIVE		1		//Check for Positive
#define NEGATIVE		-1		//Check for Negative
#define DONT_CHECK		0		//Don't Check

class CPUCore {
private:
	unsigned char cMem[0x10000];	//Memory
	REGISTERS regs;		//Registers
	unsigned char opcode;	//Current instruction
	unsigned int cycle;		//CPU cycles
	Graphics graphics;
	Inputs inputs;

	//Check flag condition
	bool checkCondition(unsigned char *condition);
	//Push Program Counter to Stack
	void pushPCtoStack();
	//Update flags after ADD and SUB instruction
	void addSubUpdateFlags(unsigned int *result, int *sign);
	//Update Z and N Flags (Use for all except ADD and SUB)
	void updateZandN(unsigned int *result);

	//All memory writes from chip16 programs MUST go through this function
	void writeMemory(unsigned char val, int addr);

	
	/**** Chip 16 Instructions ****/
	
	//Graphics
	void CLS();
	void VBLNK();
	void BGCN();
	void SPRHHLL();
	void DRWRXRYHHLL();
	void DRWRXRYRZ();
	void RNDRXHHLL();
	void FLIP();
	void PALHHLL();
	void PALRx();
	//Jumps
	void JMPHHLL();
	void JxHHLL();
	void JMERXRYHHLL();
	void JMPRX();
	//Calls
	void CALLHHLL();
	void RET();
	void CxHHLL();
	void CALLRX();
	//Loads
	void LDIRXHHLL();
	void LDISPHHLL();
	void LDMRXHHLL();
	void LDMRXRY();
	void MOVRXRY();
	//Stores
	void STMRXHHLL();
	void STMRXRY();
	//Arithmetic
	//Adds
	void addCheckSign(unsigned int *first, unsigned int *second, int *signOut);
	void ADDIRXHHLL();
	void ADDRXRY();
	void ADDRXRYRZ();
	//Subtracts
	void subCheckSign(unsigned int *first, unsigned int *second, int *signOut);
	void SUBIRXHHLL();
	void SUBRXRY();
	void SUBRXRYRZ();
	//Compares
	void CMPIRXHHLL();
	void CMPRXRY();
	//ANDs
	void ANDIRXHHLL();
	void ANDRXRY();
	void ANDRXRYRZ();
	//Tests
	void TSTIRXHHLL();
	void TSTRXRY();
	//ORs
	void ORIRXHHLL();
	void ORRXRY();
	void ORRXRYRZ();
	//XORs
	void XORIRXHHLL();
	void XORRXRY();
	void XORRXRYRZ();
	//Multiplys
	void setFlagsForMultiply(unsigned int *result);
	void MULIRXHHLL();
	void MULRXRY();
	void MULRXRYRZ();
	//Divides
	void DIVIRXHHLL();
	void DIVRXRY();
	void DIVRXRYRZ();
	//Shifts
	void SHLRXN();
	void SHRRXN();
	void SALRXN();
	void SARRXN();
	void SHLRXRY();
	void SHRRXRY();
	void SALRXRY();
	void SARRXRY();
	//Pushes
	void PUSHRX();
	void PUSHALL();
	void PUSHF();
	//Pops
	void POPRX();
	void POPALL();
	void POPF();

public:
	CPUCore(HWND hwnd, bool *startEmulation);

	//Gets
	unsigned int getPC();
	unsigned int getSP();
	unsigned char getFlag();
	unsigned int getR(int index);
	unsigned char *getMemory();
	unsigned int getCycle();
	Inputs *getInput();

	//Sets
	void setPC(int val);
	void setSP(int val);
	void setFlag(unsigned char val);
	void setR(int val, int index);
	void setMemory(unsigned char val, int addr);

	//fetch, decode, execute
	void fetchDecodeExecute();

};

#endif